package com.hhd.cwqs.qs;

import com.hhd.cwqs.entity.CwqsLog;
import com.hhd.cwqs.entity.CwqsLogDetail;
import com.hhd.cwqs.entity.CwqsUnit;
import com.hhd.cwqs.qs.service.MainProcessor;
import com.hhd.cwqs.qs.service.Processor;
import com.hhd.cwqs.service.ICwqsLogDetailService;
import com.hhd.cwqs.service.ICwqsLogService;
import com.hhd.cwqs.utils.CommonUtils;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.modules.quartz.entity.QuartzJob;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Calendar;
import java.util.List;
import java.util.stream.Collectors;

@Component
@Slf4j
public class CwqsDelegate {
    @Autowired
    ContextFactory contextFactory;

    @Autowired
    List<MainProcessor> processors;

    @Autowired
    ICwqsLogService logService;

    @Autowired
    ICwqsLogDetailService logDetailService;

    public void qsByJob(QuartzJob job) {
        String sourceDataSourceId = job.getSourceDataSourceId();
        String targetDataSourceId = job.getTargetDataSourceId();
        String unitId = job.getUnitId();
        String month = job.getMonth();
        String year = job.getYear();
        String accountingSystem = job.getAccountingSystem();
        doQs(sourceDataSourceId, targetDataSourceId, unitId, month, year, accountingSystem, job.getTaskName());
    }

    public void doQs(String sourceDataSourceId,
                      String targetDataSourceId,
                      String unitId, String month,
                      String year, String accountingSystem,
                      String jobName) {
        Context context = contextFactory.createContext(
                sourceDataSourceId,
                targetDataSourceId,
                unitId, month, year,
                accountingSystem);
        context.setJobName(jobName);
        List<String> years = context.getYears();
        List<CwqsUnit> units = context.getUnits();
        years = sortYears(years);
        sortMonth(context);
        for (String currentYear : years) {
            for (CwqsUnit unit : units) {
                try {
                    doQsJob(currentYear, unit, context);
                    context.createDetailLog(currentYear, unit, "采集成功");
                } catch (Exception e) {
                    context.createDetailLog(currentYear, unit, "采集失败: " + e.toString());
                }
            }
        }

        closeSession(context);
        saveLog(context);
    }

    private void saveLog(Context context) {
        CwqsLog log = context.getLog();
        logService.save(log);
        List<CwqsLogDetail> details = log.getDetails();
        if (!CommonUtils.isEmpty(details)) {
            for (CwqsLogDetail detail : details) {
                detail.setLogId(log.getId());
            }
            logDetailService.saveBatch(details);
        }
    }

    @NotNull
    private List<String> sortYears(List<String> years) {
        years = years.stream().map(this::resolveYear).collect(Collectors.toList());
        years.sort(String::compareToIgnoreCase);
        return years;
    }

    private void sortMonth(Context context) {
        context.getMonthes().sort((o1, o2) -> toInteger(o1).compareTo(toInteger(o2)));
    }

    private Integer toInteger(String o1) {
        try {
            return Integer.parseInt(o1.replaceAll("^0+", ""));
        } catch (Exception e) {
            return 0;
        }
    }

    private String resolveYear(String year) {
        if (year.equalsIgnoreCase("nextYear")) {
            return (Calendar.getInstance().get(Calendar.YEAR) + 1) + "";
        }
        if (year.equalsIgnoreCase("lastYear")) {
            return (Calendar.getInstance().get(Calendar.YEAR) - 1) + "";
        }
        if (year.equalsIgnoreCase("currentYear")) {
            return Calendar.getInstance().get(Calendar.YEAR) + "";
        }
        try {
            return Integer.parseInt(year) + "";
        } catch (Exception e) {
            throw new RuntimeException("年度解析失败: " + e.getMessage());
        }
    }

    private void doQsJob(String year, CwqsUnit unit, Context context) {
        boolean commit = true;
        try {
            doQsJob(createParam(year, unit, context));
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            commit = false;
            rollbackTransaction(context);
        } finally {
            if (commit) {
                commitTransaction(context);
            }
        }
    }

    private void doQsJob(Params param) {
        getProcessor(param).process(param);
    }

    private MainProcessor getProcessor(Params param) {
        for (MainProcessor processor : processors) {
            Processor annotation = CommonUtils.getAnnotation(processor, Processor.class);
            if (!CommonUtils.isEmpty(annotation) &&
                    param.getAccountingSystem().equalsIgnoreCase(annotation.accountingSystem())) {
                return processor;
            }
        }
        throw new RuntimeException("不支持的财务系统: " + param.getAccountingSystem());
    }

    private void commitTransaction(Context context) {
        context.getTargetSqlTemplate().commit();
    }

    private void rollbackTransaction(Context context) {
        context.getTargetSqlTemplate().rollback();
    }

    private void closeSession(Context context) {
        try {
            context.getTargetSqlTemplate().close();
        } catch (Exception e) {
        }

        try {
            context.getSourceSqlTemplate().close();
        } catch (Exception e) {
        }
    }

    private Params createParam(String year,
                               CwqsUnit unit,
                               Context context) {
        Params params = new Params();
        params.setContext(context);
        params.setSourceSqlTemplate(context.getSourceSqlTemplate());
        params.setTargetSqlTemplate(context.getTargetSqlTemplate());
        params.setMonthes(context.getMonthes());
        params.setYear(year);
        params.setUnit(unit);
        params.setAccountingSystem(context.getAccountingSystem());
        params.createPkBuilder();
        return params;
    }
}
